package controllers

import (
	jsoniter "github.com/json-iterator/go"
	"github.com/kataras/iris/v12"
	"github.com/kataras/iris/v12/mvc"
	"github.com/kataras/iris/v12/websocket"
	"github.com/kataras/neffos"
	"github.com/robfig/cron"
	"log"
	"math/rand"
	"penguin/model"
	"penguin/penguin"
	"penguin/response"
	"strconv"
	"sync/atomic"
	"time"
)

var PenguinLife = int64(7200)
var userFeedTime = make(map[string]int64)
var WebsocketServer = websocket.New(
	websocket.DefaultGobwasUpgrader, /* DefaultGobwasUpgrader can be used too. */
	websocket.Events{
		websocket.OnNativeMessage: func(nsConn *websocket.NSConn, msg websocket.Message) error {
			ctx := websocket.GetContext(nsConn.Conn)
			log.Printf("[%s] connected to namespace [%s] with IP [%s]",
				nsConn, msg.Namespace,
				ctx.RemoteAddr())
			return nil
		},
	},
)

type PenguinController struct {
	Ctx iris.Context
}

func (p *PenguinController) BeforeActivation(b mvc.BeforeActivation) {
	b.Handle("POST", "/feed", "Feed", beforeCommonToken)
	b.Handle("POST", "/restart", "Restart", beforeCommonToken)
	crontab := cron.New()
	crontab.AddFunc("* * * * *", func() {
		if PenguinLife > 0 {
			atomic.AddInt64(&PenguinLife, -1)
		}
		data, err := jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(map[string]interface{}{"id": 0, "penguin_life": strconv.FormatInt(PenguinLife, 10)})
		if err != nil {
			return
		}
		WebsocketServer.Broadcast(nil, websocket.Message{Body: data, IsNative: true})
	})
	crontab.AddFunc("0 0 0 * * ? ", func() {
		if PenguinLife < 7200 {
			atomic.SwapInt64(&PenguinLife, 7200)
		}
		data, err := jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(map[string]interface{}{"id": 0, "penguin_life": strconv.FormatInt(PenguinLife, 10)})
		if err != nil {
			return
		}
		WebsocketServer.Broadcast(nil, websocket.Message{Body: data, IsNative: true})
	})
	crontab.Start()
	WebsocketServer.OnConnect = func(c *neffos.Conn) error {
		log.Printf("[%s] Connected to server!", c.ID())
		return nil
	}
}

// @Title Penguin Feed
// @Description 企鹅喂食
// @Tags penguin
// @Param body body response.TokenInfo true "token"
// @Success 200	{object} response.JsonResponse "1 企鹅死了 2 点太快"
// @Failure 500 {object} response.JsonResponse "内部错误"
// @router /penguin/feed [post]
func (p *PenguinController) Feed() response.JsonResponse {
	user := p.Ctx.Values().Get("user").(model.User)
	if PenguinLife == 0 {
		return response.JsonResponse{
			ErrCode: 0,
			ErrInfo: "",
			Data: response.FeedPenguin{
				Code:        1,
				PenguinLife: 0,
			},
		}
	}
	if !user.Admin {
		feedTime, ok := userFeedTime[user.Uid]
		if ok {
			if time.Now().Unix()-feedTime < 900 {
				return response.JsonResponse{
					ErrCode: 0,
					ErrInfo: "",
					Data: response.FeedPenguin{
						Code:        2,
						PenguinLife: 0,
					},
				}
			}
		}
		userFeedTime[user.Uid] = time.Now().Unix()
	}
	lifeCount, err := p.feedPenguin()
	if err != nil {
		penguin.Error(err)
	}
	if lifeCount >= 10 {
		data, err := jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(map[string]interface{}{"id": 1, "nick_name": user.NickName, "life": strconv.FormatInt(lifeCount, 10)})
		if err != nil {
			penguin.Error(err)
		} else {
			WebsocketServer.Broadcast(nil, websocket.Message{Body: data, IsNative: true})
		}
	}
	return response.JsonResponse{
		ErrCode: 0,
		ErrInfo: "",
		Data: response.FeedPenguin{
			Code:        0,
			PenguinLife: int32(PenguinLife),
		},
	}
}

// @Title Penguin Restart
// @Description 企鹅复活至7200秒
// @Tags penguin
// @Param body body response.TokenInfo true "token"
// @Success 200	{object} response.JsonResponse ""
// @router /penguin/restart [post]
func (p *PenguinController) Restart() response.JsonResponse {
	atomic.SwapInt64(&PenguinLife, 7200)
	return response.JsonResponse{
		ErrCode: 0,
		ErrInfo: "",
		Data:    "",
	}
}

func (p *PenguinController) feedPenguin() (lifeCount int64, err error) {
	randNumber := rand.Int31n(100)
	if randNumber <= 10 {
		lifeCount = 100
	} else if randNumber <= 30 {
		lifeCount = 10
	} else {
		lifeCount = 1
	}
	atomic.AddInt64(&PenguinLife, lifeCount)
	data, err := jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(map[string]interface{}{"id": 0, "penguin_life": strconv.FormatInt(PenguinLife, 10)})
	if err != nil {
		return
	}
	WebsocketServer.Broadcast(nil, websocket.Message{Body: data, IsNative: true})
	return
}
